﻿using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace Llkd
{
    public partial class FrmMain : Form
    {
        string strAllScreenFileName
        {
            get
            {
                if (Directory.Exists("r:\\"))
                {
                    return "r:\\zAll.bmp";
                }
                else
                {
                    return AppDomain.CurrentDomain.BaseDirectory + "\\zAll.bmp";  //"c:\\zAll.bmp";
                }
                //return code;
            }
        }

        const int int_Xnum = 14;
        const int int_Ynum = 10;
        int int_SideLength_X = 0;
        int int_SideLength_Y = 0;
        Mat matKongBai;
        //Bitmap bitmapKongBai;
        //string strImageHashCode_KongBai;
        Dictionary<int, bool> dicIsBlock = new Dictionary<int, bool>(200);

        List<MyPoint> lstPoint140 = new List<MyPoint>();

        System.Drawing.Point pLeftTop = new System.Drawing.Point(0, 0);
        System.Drawing.Point pBottomRight = new System.Drawing.Point(0, 0);
        /// <summary>
        /// 鼠标控制参数
        /// </summary>
        //private readonly int MOUSEEVENTF_MOVE = 0x0001;//模拟鼠标左键按下
        private readonly int MOUSEEVENTF_LEFTDOWN = 0x0002;//模拟鼠标移动
        private readonly int MOUSEEVENTF_LEFTUP = 0x0004;//模拟鼠标左键抬起
        //private readonly int MOUSEEVENTF_ABSOLUTE = 0x8000;//鼠标绝对位置
        //private readonly int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模拟鼠标右键按下 
        //private readonly int MOUSEEVENTF_RIGHTUP = 0x0010; //模拟鼠标右键抬起 
        //private readonly int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模拟鼠标中键按下 
        //private readonly int MOUSEEVENTF_MIDDLEUP = 0x0040;// 模拟鼠标中键抬起

        //private void button2_Click(object sender, EventArgs e)
        //{
        //    //int x = int.Parse(textBox1.Text); int y = int.Parse(textBox2.Text);
        //    //绝对位置      
        //    mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, x * 65535 / 1600, y * 65535 / 900, 0, 0);
        //    //移动到需要点击的位置     
        //    mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE, x * 65535 / 1600, y * 65535 / 900, 0, 0);
        //    //点击     
        //    mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, x * 65535 / 1600, y * 65535 / 900, 0, 0);
        //    //抬起
        //    //相对位置  指的是相对于当前鼠标的相对位置

        //    mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);//移动 
        //    mouse_event(MOUSEEVENTF_LEFTDOWN , x , y, 0, 0);//点击    
        //    mouse_event(MOUSEEVENTF_LEFTUP , x , y , 0, 0);//抬起
        //}

        /// <summary>
        /// 鼠标的位置
        /// </summary>
        public struct PONITAPI
        {
            public int x, y;
        }

        [DllImport("user32.dll")]
        public static extern int GetCursorPos(ref PONITAPI p);

        [DllImport("user32.dll")]
        public static extern int SetCursorPos(int x, int y);

        [DllImport("user32.dll")]
        public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

        [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        private static extern int GetDC(int hwnd);

        [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] //确定坐标
        private static extern int ReleaseDC(int hwnd, int hdc);

        //PONITAPI P; //确定坐标

        [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        private static extern int ScreenToClient(int hwnd, ref PONITAPI lpPoint);
        [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        private static extern int WindowFromPoint(int xPoint, int yPoint);

        [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        private static extern int GetPixel(int hdc, int X, int y);

        public FrmMain()
        {
            InitializeComponent();
        }
        private void FrmMain_Load(object sender, EventArgs e)
        {
            ZdsLog.Del_Log();
            ZdsLog.Init_log();

            //string strAllScreenFileName = "r:\\zAll.bmp";
            //if (Directory.Exists ("r:\\"))
            //{

            //}else
            //{
            //    strAllScreenFileName = AppDomain.CurrentDomain.BaseDirectory + "\\zAll.bmp";  //"c:\\zAll.bmp";
            //}

            FileInfo fiAllScreenFileName = new FileInfo(strAllScreenFileName);
            if (fiAllScreenFileName.Exists)
            {
                fiAllScreenFileName.Delete();
            }

            string strKongBaiFileName = AppDomain.CurrentDomain.BaseDirectory + "\\kongbai.bmp";
            strKongBaiFileName = strKongBaiFileName.Replace("\\\\", "\\");
            FileInfo fiLog5 = new FileInfo(strKongBaiFileName);
            if (fiLog5.Exists)
            {
                this.lblKongBaiPath.Text = strKongBaiFileName;
                //bitmapKongBai = new Bitmap(strKongBaiFileName);
                matKongBai = new Mat(strKongBaiFileName, ImreadModes.Color);
                //strImageHashCode_KongBai = ImageComparer.GetImageHashCode(strKongBaiFileName);
            }
            else
            {
                this.lblKongBaiPath.Text = "No kongbai.bmp file!";
            }

            int m, n, i_key;

            for (m = 0; m <= int_Xnum + 1; m++)
            {
                for (n = 0; n <= int_Ynum + 1; n++)
                {
                    i_key = (m + 1) * 1000 + n + 1;
                    dicIsBlock.Add(i_key, false);
                }
            }

        }

        /// <summary>
        /// 复制屏幕到内存中
        /// </summary>
        /// <returns>返回内存流</returns>
        public static MemoryStream GetScreenPng()
        {
            Screen sc = Screen.PrimaryScreen;//取得主屏

            Rectangle rct = sc.Bounds;//得到主屏的范围
            Image img = new Bitmap(rct.Width, rct.Height);
            Graphics gp = Graphics.FromImage(img);
            gp.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), new System.Drawing.Size(rct.Width, rct.Height));


            //SolidBrush sb = new SolidBrush(Color.Red);
            //Font ft = new System.Drawing.Font("黑体",16);

            //gp.DrawString("这是什么",ft,sb,new PointF(0,rct.Height-ft.Height));
            //img.Save(@"d:\截图.png");

            MemoryStream stream = new MemoryStream();
            img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);//转化为流，此时就已经有了png格式符了

            return stream;
        }

        /// <summary>
        /// 复制整个屏幕到文件中
        /// </summary>
        public static void GetAllScreenBmpToFile()
        {
            Screen sc = Screen.PrimaryScreen;//取得主屏

            Rectangle rct = sc.Bounds;//得到主屏的范围
            Image img = new Bitmap(rct.Width, rct.Height);
            Graphics gp = Graphics.FromImage(img);
            gp.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), new System.Drawing.Size(rct.Width, rct.Height));

            //SolidBrush sb = new SolidBrush(Color.Red);
            //Font ft = new System.Drawing.Font("黑体",16);

            //gp.DrawString("这是什么",ft,sb,new PointF(0,rct.Height-ft.Height));

            string sAllScreenFileName = "r:\\zAll.bmp";
            if (Directory.Exists("r:\\"))
            {
            }
            else
            {
                sAllScreenFileName = AppDomain.CurrentDomain.BaseDirectory + "\\zAll.bmp";  //"c:\\zAll.bmp";
            }

            //img.Save(@"r:\zAll.bmp");
            img.Save(sAllScreenFileName);


            //MemoryStream stream = new MemoryStream();
            //img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);//转化为流，此时就已经有了png格式符了

            //return stream;
        }

        /// <summary>
        /// 复制矩形屏幕到文件中
        /// </summary>
        /// <returns>返回内存流</returns>
        public static void SaveSomeScreenBmp(int x0, int y0, int iWidth, int iHeight, string strFileName)
        {
            //System.Drawing.Point p = new System.Drawing.Point(0, 0);
            //System.Drawing.Point p;
            //Screen scr;
            //= Screen.PrimaryScreen;//获取到主显示器
            //Rectangle rc;//= new Rectangle(0, 0, iWidth, iHeight); // scr.Bounds;  //获取到它的边界
            //创建一个和屏幕一样大的  Bitmap
            Image myImage = new Bitmap(iWidth, iHeight);
            //从一个继承自Image类的对象中创建Graphics对象            
            Graphics g = Graphics.FromImage(myImage);
            //抓屏并拷贝到myimage里
            g.CopyFromScreen(x0, y0, 0, 0, new System.Drawing.Size(iWidth, iHeight));

            //保存为文件
            myImage.Save(strFileName);

            //SolidBrush sb = new SolidBrush(Color.Red);
            //Font ft = new System.Drawing.Font("黑体",16);

            //gp.DrawString("这是什么",ft,sb,new PointF(0,rct.Height-ft.Height));
            //img.Save(@"d:\截图.png");
        }

        /// <summary>
        /// 查找 左上角 红点
        /// </summary>
        /// <returns>返回Point </returns>
        public System.Drawing.Point GetTopLeftRedPoint(int x0, int y0, int iWidth, int iHeight)
        {
            System.Drawing.Point p = new System.Drawing.Point(0, 0);
            //Screen scr = Screen.PrimaryScreen;//获取到主显示器
            //Rectangle rc = new Rectangle(0, 0, iWidth, iHeight); // scr.Bounds;  //获取到它的边界
            //创建一个和屏幕一样大的  Bitmap
            Image myImage = new Bitmap(iWidth, iHeight);
            //从一个继承自Image类的对象中创建Graphics对象            
            Graphics g = Graphics.FromImage(myImage);
            //抓屏并拷贝到myimage里
            g.CopyFromScreen(x0, y0, 0, 0, new System.Drawing.Size(iWidth, iHeight));

            Bitmap bmp = new Bitmap(myImage);

            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    Color c = bmp.GetPixel(x, y);//取指定点颜色 
                    if (c.R > 100 && c.G < 50 && c.B < 50)
                    {
                        p.X = x; p.Y = y;
                        return p;
                    }

                }
            }

            //保存为文件
            //myImage.Save("D://cutscreen.jpg");
            return p;
        }

        /// <summary>
        /// 查找 右下角 红点
        /// </summary>
        /// <returns>返回Point </returns>
        public System.Drawing.Point GetBottomRightRedPoint(int x0, int y0, int iWidth, int iHeight)
        {
            System.Drawing.Point p = new System.Drawing.Point(0, 0);
            //Screen scr = Screen.PrimaryScreen;//获取到主显示器
            //Rectangle rc = new Rectangle(0, 0, iWidth, iHeight); // scr.Bounds;  //获取到它的边界
            //创建一个和屏幕一样大的  Bitmap
            Image myImage = new Bitmap(iWidth, iHeight);
            //从一个继承自Image类的对象中创建Graphics对象            
            Graphics g = Graphics.FromImage(myImage);
            //抓屏并拷贝到myimage里
            g.CopyFromScreen(x0, y0, 0, 0, new System.Drawing.Size(iWidth, iHeight));

            Bitmap bmp = new Bitmap(myImage);

            for (int x = bmp.Width - 1; x > 0; x--)
            {
                for (int y = bmp.Height - 1; y > 0; y--)
                {
                    Color c = bmp.GetPixel(x, y);//取指定点颜色 
                    if (c.R > 100 && c.G < 50 && c.B < 50)
                    {
                        p.X = x; p.Y = y;
                        return p;
                    }
                }
            }

            //保存为文件
            //myImage.Save("D://cutscreen.jpg");
            return p;
        }

        /// <summary>
        /// （2）以窗体FormA为例，介绍HotKey类的使用 在FormA的Activate事件中注册热键，
        /// 本例中注册 Alt + F2，Alt + F3，Alt + F6 这三个热键。这里的Id号可任意设置，但要保证不被重复。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmMain_Activated(object sender, EventArgs e)
        {
            //注册热键Alt+F2，Id号为100。HotKey.KeyModifiersAlt也可以直接使用数字1来表示。//.Shift也可以直接使用数字4来表示。
            ZdsHotKey.RegisterHotKey(Handle, 100, ZdsHotKey.KeyModifiers.Alt, Keys.F2);
            //注册热键Alt+F3，Id号为101。HotKey.KeyModifiersAlt也可以直接使用数字1来表示。//.Ctrl也可以直接使用数字2来表示。
            ZdsHotKey.RegisterHotKey(Handle, 101, ZdsHotKey.KeyModifiers.Alt, Keys.F3);
            //注册热键Alt+F6，Id号为102。HotKey.KeyModifiers.Alt也可以直接使用数字1来表示。
            //ZdsHotKey.RegisterHotKey(Handle, 102, ZdsHotKey.KeyModifiers.Alt, Keys.F6);
            ZdsHotKey.RegisterHotKey(Handle, 102, ZdsHotKey.KeyModifiers.None, Keys.F7);
        }

        /// <summary>
        /// 在FormA的Leave事件中注销热键。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmMain_Leave(object sender, EventArgs e)
        {
            //注销Id号为100的热键设定
            ZdsHotKey.UnregisterHotKey(Handle, 100);
            //注销Id号为101的热键设定
            ZdsHotKey.UnregisterHotKey(Handle, 101);
            //注销Id号为102的热键设定
            ZdsHotKey.UnregisterHotKey(Handle, 102);
        }


        /// 监视Windows消息 重载WndProc方法，用于实现热键响应
        protected override void WndProc(ref Message m)
        {
            const int WM_HOTKEY = 0x0312;
            //按快捷键 
            switch (m.Msg)
            {
                case WM_HOTKEY:
                    switch (m.WParam.ToInt32())
                    {
                        case 100:    //按下的是 Alt + F2
                                     //此处填写快捷键响应代码 
                            ZdsGetMousePosF2();
                            break;
                        case 101:    //按下的是 Alt + F3
                                     //此处填写快捷键响应代码
                            ZdsGetMousePosF3();
                            break;
                        case 102:    //按下的是 Alt + F6
                                     //此处填写快捷键响应代码
                            ZdsMoveMouse();
                            break;
                    }
                    break;
            }
            base.WndProc(ref m);
        }
        /// <summary>
        /// 得到 左上角的 坐标
        /// </summary>
        private void ZdsGetMousePosF2()
        {
            //Screen sc = Screen.PrimaryScreen ;//取得主屏
            Rectangle rct = Screen.PrimaryScreen.Bounds;//得到主屏的范围

            PONITAPI p = new PONITAPI();
            GetCursorPos(ref p);

            if (p.x < rct.Width / 2 && p.y < rct.Height / 2)
            {
                int x0 = p.x - 35; int y0 = p.y - 35;
                System.Drawing.Point p1;

                p1 = GetTopLeftRedPoint(x0, y0, 35, 35);

                //Point pp = new Point(0, 0);
                pLeftTop.X = x0 + p1.X;
                pLeftTop.Y = y0 + p1.Y;
                this.tbTopPosX.Text = pLeftTop.X.ToString();
                this.tbTopPosY.Text = pLeftTop.Y.ToString();

                SetCursorPos(pLeftTop.X, pLeftTop.Y);

            }
            else
            {
                System.Drawing.Point p1;
                p1 = GetBottomRightRedPoint(p.x, p.y, 35, 35);

                pBottomRight.X = p.x + p1.X;
                pBottomRight.Y = p.y + p1.Y;
                this.tbBottomPosX.Text = pBottomRight.X.ToString();
                this.tbBottomPosY.Text = pBottomRight.Y.ToString();

                //SetCursorPos(pBottomRight.X, pBottomRight.Y);
            }

            if (pLeftTop.X > 2 && pLeftTop.Y > 2 && pBottomRight.X > 100 && pBottomRight.Y > 100)
            {
                double double_SideLength_X = Math.Ceiling((pBottomRight.X - pLeftTop.X) * 1.0f / (int_Xnum * 1.0f));
                double double_SideLength_Y = Math.Ceiling((pBottomRight.Y - pLeftTop.Y) / (int_Ynum * 1.0f));

                int_SideLength_X = int.Parse(double_SideLength_X.ToString());
                int_SideLength_Y = int.Parse(double_SideLength_Y.ToString());

                pLeftTop.X = pBottomRight.X - int_SideLength_X * int_Xnum;
                pLeftTop.Y = pBottomRight.Y - int_SideLength_Y * int_Ynum;

                ZdsLog.WriteLog("X = " + pLeftTop.X.ToString() + " - " + pBottomRight.X.ToString());
                ZdsLog.WriteLog("Y = " + pLeftTop.Y.ToString() + " -  " + pBottomRight.Y.ToString());

                ZdsLog.WriteLog("SideLength_X = " + int_SideLength_X.ToString() + "   SideLength_Y = " + int_SideLength_Y.ToString());

                SetCursorPos(pLeftTop.X, pLeftTop.Y);

            }

        }

        /// <summary>
        /// 得到 右下角的 坐标
        /// </summary>
        private void ZdsGetMousePosF3()
        {
            //PONITAPI p = new PONITAPI();
            //GetCursorPos(ref p);

            //int int_SideLength_Xc2 = int.Parse(Math.Ceiling(double_SideLength_X / 2.0f).ToString());
            //int int_SideLength_Yc2 = int.Parse(Math.Ceiling(double_SideLength_Y / 2.0f).ToString());

            //ZdsLog.WriteLog("int_SideLength_Xc2 = " + int_SideLength_Xc2.ToString());
            //ZdsLog.WriteLog("int_SideLength_Yc2 = " + int_SideLength_Yc2.ToString());

        }

        /// <summary>
        /// 移动 鼠标 到 
        /// </summary>
        private void ZdsMoveMouse()
        {
            int i_key, m, n, x, y, kk, x_step = 4, y_step = 4;
            int b, c, d; // a,
            List<MyPoint> lstPoint6 = new List<MyPoint>();
            StringBuilder sb1 = new StringBuilder();
            lstPoint140.Clear();

            for (m = 0; m <= int_Xnum + 1; m++)
            {
                for (n = 0; n <= int_Ynum + 1; n++)
                {
                    i_key = (m + 1) * 1000 + n + 1;
                    dicIsBlock[i_key] = false;
                }
            }
            //foreach (int  item in dicIsBlock.Keys)
            //{
            //    sb1.Append(item+" ,");
            //}
            //ZdsLog.WriteLog(sb1.ToString());


            GetAllScreenBmpToFile();

            //Mat matAllScreen = new Mat(@"r:\zAll.bmp", ImreadModes.Grayscale);
            Mat matAllScreen = new Mat(strAllScreenFileName, ImreadModes.Grayscale);

            for (m = 1; m <= int_Xnum; m++)
            {
                for (n = 1; n <= int_Ynum; n++)
                {
                    i_key = (m + 1) * 1000 + n + 1;
                    x = pLeftTop.X + x_step + (m - 1) * int_SideLength_X;
                    y = pLeftTop.Y + y_step + (n - 1) * int_SideLength_Y;

                    //检查是否是 空白 图像
                    Rect roi = new Rect(x, y, int_SideLength_X - 6, int_SideLength_Y - 5);//首先要用个rect确定我们的兴趣区域在哪
                    Mat matCeShi = new Mat(matAllScreen, roi);//新建一个mat，把roi内的图像加载到里面去。

                    //string strFileName = "r:\\k" + i_key.ToString() + ".bmp";
                    //matCeShi.SaveImage(strFileName);

                    bool bool_isKongBai = GzHxsf(matKongBai, matCeShi);
                    if (bool_isKongBai)
                    {
                        //ZdsLog.WriteLog(string.Format("空白图像 i = {0} M_N = ( {1}, {2} ) ", ii, m, n));
                        //dicBlock[ii] = false;                       
                        //dicIsBlock[strKey] = false;
                    }
                    else
                    {
                        //ZdsLog.WriteLog(string.Format("图像 i = {0} M_N = ( {1}, {2} ) ", ii, m, n));
                        //i_key = (m + 1) * int_Xnum + n + 1;
                        dicIsBlock[i_key] = true;

                        int[] arr1;//= new int[64];
                        arr1 = GetGzHx(matCeShi);

                        MyPoint p_xy = new MyPoint(i_key, x, y, m, n, arr1);
                        //p_xy.Mat = matCeShi;

                        lstPoint140.Add(p_xy);
                    }
                }
            }

            ZdsLog.WriteLog(string.Format("去空白图像后：lstPoint140.Count = {0} ", lstPoint140.Count));

        //for (m = 0; m <= int_Xnum + 1; m++)
        //{
        //    for (n = 0; n <= int_Ynum + 1; n++)
        //    {
        //        //i_key = (m + 1) * int_Xnum + n + 1;
        //        s_key = string.Format("{0}_{1}", m, n);
        //        //dicIsBlock[s_key] = false;
        //        ZdsLog.WriteLog(s_key + "_block_" + dicIsBlock[s_key].ToString());
        //    }
        //}


        //foreach (MyPoint pItem1 in lstPoint140)
        //{
        //    sb1.Clear();
        //    for (int i = 0; i < 64; i++)
        //    {
        //        sb1.Append(pItem1.GzhsTzz[i].ToString());
        //    }
        //    ZdsLog.WriteLog(string.Format("key = {0} M_N = ( {1}, {2} ) X_Y = ( {3}, {4} ) GzhsTzz = {5} ", pItem1.Key, pItem1.M, pItem1.N, pItem1.X, pItem1.Y, sb1.ToString()));
        //    // pItem1.Mat.SaveImage(pItem1.strFileName);
        //}

        //ZdsLog.WriteLog("\r\n");            //ZdsLog.WriteLog("Line = 435");            //ZdsLog.WriteLog("\r\n\r\n");


        start_precess:
            if (lstPoint140.Count < 1)
            {
                return;
            }

            //for (a = 0; a < lstPoint140.Count; a++)
            //{
            //int i = pItem2.i;
            //Mat src = new Mat(pItem2.strFileName, ImreadModes.Color);
            //ZdsLog.WriteLog("Line = 444");
            //ZdsLog.WriteLog("lstPoint140.Count = " + lstPoint140.Count );
            ZdsLog.WriteLog(string.Format("\r\n有效图像：lstPoint140.Count = {0} ", lstPoint140.Count));

            MyPoint pItem = lstPoint140[0];
            //lstPoint6.Clear();
            lstPoint6.Add(pItem);

            for (b = 1; b < lstPoint140.Count; b++)
            {
                ////int i2 = lstPoint140[a].i;

                ////Mat src2 = new Mat(lstPoint140[a].strFileName, ImreadModes.Color);
                //float float_Similar1 = Similar(pItem.Mat, lstPoint140[b].Mat);

                ////ZdsLog.WriteLog("Line = 462");
                ////ZdsLog.WriteLog( string.Format (" i = {0} 与 lstPoint140[a].i = {1}   float_Similar1 = {2}" , pItem2.i,a, float_Similar1));

                //if (float_Similar1 > 0.9)
                //{
                //    //this.tbResult.Text = this.tbResult.Text + strFileName2 + float_Similar1.ToString() + "\r\n\r\n";
                //    lstPoint6.Add(lstPoint140[b]);
                //}

                int iDiffNum = Gzhs_hs(pItem.GzhsTzz, lstPoint140[b].GzhsTzz);
                if (iDiffNum <= 6)
                {
                    //sb1.Clear();
                    //for (int i = 0; i < 64; i++)
                    //{
                    //    sb1.Append(pItem.GzhsTzz[i].ToString());
                    //}
                    //ZdsLog.WriteLog(string.Format("pItem          key = {0} M_N = ( {1}, {2} ) X_Y = ( {3}, {4} ) GzhsTzz = {5} ", pItem.Key, pItem.M, pItem.N, pItem.X, pItem.Y, sb1.ToString()));

                    //sb1.Clear();
                    //for (int i = 0; i < 64; i++)
                    //{
                    //    sb1.Append(lstPoint140[b].GzhsTzz[i].ToString());
                    //}
                    //ZdsLog.WriteLog(string.Format("lstPoint140[b] key = {0} M_N = ( {1}, {2} ) X_Y = ( {3}, {4} ) GzhsTzz = {5} ", lstPoint140[b].Key, lstPoint140[b].M, lstPoint140[b].N, lstPoint140[b].X, lstPoint140[b].Y, sb1.ToString()));
                    //ZdsLog.WriteLog(string.Format("iDiffNum = {0} \r\n", iDiffNum));

                    //this.tbResult.Text = this.tbResult.Text + strFileName2 + float_Similar1.ToString() + "\r\n\r\n";
                    lstPoint6.Add(lstPoint140[b]);
                }
            }

            //foreach (MyPoint pitem3 in lstPoint6)
            //{
            //    ZdsLog.WriteLog(string.Format("i = {0} M_N = ( {1}, {2} ) ", pitem3.i, pitem3.m, pitem3.n));
            //}
            //ZdsLog.WriteLog("相同\r\n");
            //ZdsLog.WriteLog(string.Format("i = {0} M_N = ( {1} , {2} )", pItem.Key, pItem.M, pItem.N));
            ZdsLog.WriteLog("lstPoint6.Count = " + lstPoint6.Count);

            for (c = 0; c < lstPoint6.Count; c++)
            {
                for (d = c + 1; d < lstPoint6.Count; d++)
                {
                    bool boolIsScesses = Horizon(lstPoint6[c].M, lstPoint6[c].N, lstPoint6[d].M, lstPoint6[d].N);

                    //ZdsLog.WriteLog(string.Format("i = {0} M_N = ( {1}, {2} ) horizon i2 = {3} X_Y = ( {4}, {5} )  boolIsScesses = {6}",
                    //    pitem4.i, pitem4.m, pitem4.n, pitem5.i, pitem5.m, pitem5.n, boolIsScesses));

                    if (boolIsScesses)
                    {
                        XiaoLLK(lstPoint6[c], lstPoint6[d]);
                        return;
                    }

                    boolIsScesses = Vertical(lstPoint6[c].M, lstPoint6[c].N, lstPoint6[d].M, lstPoint6[d].N);
                    if (boolIsScesses)
                    {
                        XiaoLLK(lstPoint6[c], lstPoint6[d]);
                        return;
                    }

                    boolIsScesses = Turn_once(lstPoint6[c].M, lstPoint6[c].N, lstPoint6[d].M, lstPoint6[d].N);
                    if (boolIsScesses)
                    {
                        XiaoLLK(lstPoint6[c], lstPoint6[d]);
                        return;
                    }

                    boolIsScesses = Turn_twice(lstPoint6[c].M, lstPoint6[c].N, lstPoint6[d].M, lstPoint6[d].N);
                    if (boolIsScesses)
                    {
                        XiaoLLK(lstPoint6[c], lstPoint6[d]);
                        return;
                    }
                }
            }

            foreach (MyPoint pitem3 in lstPoint6)
            {
                lstPoint140.Remove(pitem3);
                //ZdsLog.WriteLog(string.Format("i = {0} M_N = ( {1}, {2} ) ", pitem3.i, pitem3.m, pitem3.n));
            }
            lstPoint6.Clear();

            kk = lstPoint140.Count;
            if (kk > 1)
            {
                kk--;
                SetCursorPos(lstPoint140[kk].X, lstPoint140[kk].Y);
            }

            ZdsLog.WriteLog("再次计算");
            goto start_precess; //返回 start_precess 标签处重新开始处理

            //break;
            //}
        }

        public void XiaoLLK(MyPoint pitem4, MyPoint pitem5)
        {
            SetCursorPos(pitem4.X + 15, pitem4.Y + 15);

            //移动到 需要点击的绝对位置      
            //mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pItem.X * 65535 / 1600, pItem.Y * 65535 / 900, 0, 0);
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//点击 并且 抬起   

            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//点击 并且 抬起    

            ZdsLog.WriteLog(string.Format("i = {0} M_N = ( {1}, {2} ) <-----> i2 = {3} X_Y = ( {4}, {5} ) ", pitem4.Key, pitem4.M, pitem4.N,
                                    pitem5.Key, pitem5.M, pitem5.N));
            //ZdsLog.WriteLog(string.Format("Point = ( {0}, {1} ) ", pItem.X, pItem.Y));
            SetCursorPos(pitem5.X + 15, pitem5.Y + 15);

            //移动到 需要点击的绝对位置      
            //mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pItem.X * 65535 / 1600, pItem.Y * 65535 / 900, 0, 0);
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//点击 并且 抬起

            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//点击 并且 抬起    
        }


        //成对几何直方图匹配 
        public float Similar(Mat graySrc1, Mat graySrc2)
        {
            var size = new OpenCvSharp.Size(512, 512);
            using (var scaledImg1 = graySrc1.Resize(size))
            using (var scaledImg2 = graySrc2.Resize(size))
            {
                Cv2.Threshold(scaledImg1, scaledImg1, 128, 255, ThresholdTypes.BinaryInv);
                Cv2.Threshold(scaledImg2, scaledImg2, 128, 255, ThresholdTypes.BinaryInv);
                Mat res = new Mat(size, scaledImg1.Type());
                Cv2.Absdiff(scaledImg1, scaledImg2, res);
                //Cv2.ImShow("aa", scaledImg1);
                var all = (float)scaledImg1.Sum();
                var result = (float)res.Sum();
                //print("result:" + (1 - result / all));
                return (1 - result / all);
            }
        }

        // 感知哈希算法 OpenCV
        //如果不相同的数据位数不超过5，就说明两张图像很相似；如果大于10，就说明这是两张不同的图像。
        bool GzHxsf(Mat graySrc1, Mat graySrc2)
        {
            //OpenCvSharp.Size size = new OpenCvSharp.Size(8, 8);
            Mat matDst1 = new Mat(); Mat matDst2 = new Mat();
            Cv2.Resize(graySrc1, matDst1, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);
            Cv2.Resize(graySrc2, matDst2, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);

            int iAvg1 = 0, iAvg2 = 0;
            int[] arr1 = new int[64]; int[] arr2 = new int[64];

            for (int row = 0; row < 8; row++)
            {
                int tmp = row * 8;
                for (int col = 0; col < 8; col++)
                {
                    byte p1 = matDst1.At<byte>(row, col); //获对应矩阵坐标的取像素
                    byte p2 = matDst2.At<byte>(row, col); //获对应矩阵坐标的取像素
                                                          //byte value = byte.Parse((255 - p).ToString()); //反转像素值
                                                          //dst.Set(row, col, value); //赋值
                    int tmp1 = tmp + col;
                    arr1[tmp1] = p1 / 4 * 4;
                    arr2[tmp1] = p2 / 4 * 4;

                    iAvg1 += arr1[tmp1];
                    iAvg2 += arr2[tmp1];
                }
            }

            iAvg1 /= 64;
            iAvg2 /= 64;

            for (int i = 0; i < 64; i++)
            {
                arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
                arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
            }

            int iDiffNum = 0;

            for (int i = 0; i < 64; i++)
                if (arr1[i] != arr2[i])
                    ++iDiffNum;

            //cout << "iDiffNum = " << iDiffNum << endl;

            if (iDiffNum <= 5)
            {
                return true;
                //cout << "two images are very similar!" << endl;
            }
            else if (iDiffNum > 10)
            {
                return false; //cout << "they are two different images!" << endl;
            }
            else
            {
                return false;
                //cout << "two image are somewhat similar!" << endl;
            }
        }

        // 感知哈希算法 OpenCV
        //如果不相同的数据位数不超过5，就说明两张图像很相似；如果大于10，就说明这是两张不同的图像。
        int[] GetGzHx(Mat graySrc1)
        {
            //OpenCvSharp.Size size = new OpenCvSharp.Size(8, 8);
            Mat matDst1 = new Mat();
            Cv2.Resize(graySrc1, matDst1, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);

            int iAvg1 = 0;
            int[] arr1 = new int[64];

            for (int row = 0; row < 8; row++)
            {
                int tmp = row * 8;
                for (int col = 0; col < 8; col++)
                {
                    byte p1 = matDst1.At<byte>(row, col); //获对应矩阵坐标的取像素
                    int tmp1 = tmp + col;
                    arr1[tmp1] = p1 / 4 * 4;

                    iAvg1 += arr1[tmp1];
                }
            }

            iAvg1 /= 64;

            for (int i = 0; i < 64; i++)
            {
                arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
            }

            return arr1;
        }

        int Gzhs_hs(int[] arr1, int[] arr2)
        {
            int iDiffNum = 0;

            for (int i = 0; i < 64; i++)
                if (arr1[i] != arr2[i])
                    ++iDiffNum;

            //cout << "iDiffNum = " << iDiffNum << endl;
            return iDiffNum;
        }

        public bool IsBlocked(int m, int n)
        {
            int i_key = (m + 1) * 1000 + n + 1;
            //string s_key = string.Format("{0}_{1}", m, n);
            return dicIsBlock[i_key];
        }
        //int isBlocked(int m, int n);
        //return 0;       // 无障碍物（位置(x,y)为空）
        //return 1;       // 有障碍物（位置(x,y)上有方块或圈圈）

        /// <summary>
        /// 垂直检测
        /// </summary>
        /// <param name="m1"></param>
        /// <param name="n1"></param>
        /// <param name="m2"></param>
        /// <param name="n2"></param>
        /// <returns></returns>
        public bool Horizon(int m1, int n1, int m2, int n2)
        {
            if (m1 == m2 && n1 == n2)
            {
                return false;
            }

            if (m1 != m2)
            {
                return false;
            }

            int start_y = Math.Min(n1, n2);
            int end_y = Math.Max(n1, n2);

            if (start_y + 1 == end_y)
            {
                return true;
            }

            for (int j = start_y + 1; j < end_y; j++)
            {
                if (IsBlocked(m1, j))
                {
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// 水平检测
        /// </summary>
        /// <param name="m1"></param>
        /// <param name="n1"></param>
        /// <param name="m2"></param>
        /// <param name="n2"></param>
        /// <returns></returns>
        public bool Vertical(int m1, int n1, int m2, int n2)
        {
            if (m1 == m2 && n1 == n2)
            {
                return false;
            }

            if (n1 != n2)
            {
                return false;
            }

            int start_x = Math.Min(m1, m2);
            int end_x = Math.Max(m1, m2);

            if (start_x + 1 == end_x)
            {
                return true;
            }

            for (int i = start_x + 1; i < end_x; i++)
            {
                if (IsBlocked(i, n1))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 一个拐角检测
        /// </summary>
        /// <param name="m1"></param>
        /// <param name="n1"></param>
        /// <param name="m2"></param>
        /// <param name="n2"></param>
        /// <returns></returns>
        public bool Turn_once(int m1, int n1, int m2, int n2)
        {
            if (m1 == m2 && n1 == n2)
            {
                return false;
            }

            int c_x = m1, c_y = n2;
            int d_x = m2, d_y = n1;

            //bool ret = false;
            if (!IsBlocked(c_x, c_y))
            {
                if (Horizon(m1, n1, c_x, c_y) && Vertical(c_x, c_y, m2, n2))
                {
                    return true;
                }
            }

            if (!IsBlocked(d_x, d_y))
            {
                if (Vertical(m1, n1, d_x, d_y) && Horizon(d_x, d_y, m2, n2))
                {
                    return true;
                }
            }
            //if (ret)
            //{
            //    return true;
            //}

            return false;
        }

        public bool Turn_twice(int x1, int y1, int x2, int y2)
        {
            if (x1 == x2 && y1 == y2)
            {
                return false;
            }

            for (int i = 0; i <= int_Xnum + 1; i++)
            {
                for (int j = 0; j <= int_Ynum + 1; j++)
                {
                    if (i != x1 && i != x2 && j != y1 && j != y2)
                    {
                        continue;
                    }

                    if ((i == x1 && j == y1) || (i == x2 && j == y2))
                    {
                        continue;
                    }

                    if (IsBlocked(i, j))
                    {
                        continue;
                    }

                    if (Turn_once(x1, y1, i, j) && (Horizon(i, j, x2, y2) || Vertical(i, j, x2, y2)))
                    {
                        return true;
                    }
                    if (Turn_once(i, j, x2, y2) && (Horizon(x1, y1, i, j) || Vertical(x1, y1, i, j)))
                    {
                        return true;
                    }

                }
            }

            return false;
        }
    }
}
